#include <jni.h>
#include <cwchar>
#include <math.h>
#include "net_qiujuer_lame_Lame.h"
#include "libmp3lame/lame.h"
#include <android/log.h>
// 需要包含 ID3 标签头文件
#include <id3tag.h>

extern "C"


JNIEXPORT jlong JNICALL
Java_net_qiujuer_lame_Lame_nInit(JNIEnv *env, jclass type, jint inSampleRate, jint inChannels,
                                 jint outSampleRate, jint outBitrate, jint model, jint quality) {
    // 添加日志
    __android_log_print(ANDROID_LOG_DEBUG, "Lame Init",
                        "nInit: inSR=%d, inCh=%d, outSR=%d, bitrate=%d, model=%d, quality=%d",
                        inSampleRate, inChannels, outSampleRate, outBitrate, model, quality);

    lame_global_flags *lameFlags = lame_init();
    if (!lameFlags) {
        __android_log_print(ANDROID_LOG_ERROR, "Lame Init", "lame_init failed");
        return 0;
    }

    lame_set_in_samplerate(lameFlags, inSampleRate);
    lame_set_num_channels(lameFlags, inChannels);
    lame_set_out_samplerate(lameFlags, outSampleRate);
    lame_set_brate(lameFlags, outBitrate);
    lame_set_mode(lameFlags, (MPEG_mode) model);
    lame_set_quality(lameFlags, quality);

    int code = lame_init_params(lameFlags);
    if (code != 0) {
        __android_log_print(ANDROID_LOG_ERROR, "Lame Init", "lame_init_params failed: %d", code);
        lame_close(lameFlags);
        return 0;
    }

    __android_log_print(ANDROID_LOG_INFO, "Lame Init", "LAME initialized successfully");
    return (jlong) lameFlags;
}

JNIEXPORT jint JNICALL
Java_net_qiujuer_lame_Lame_nGetVersion(JNIEnv *env, jclass type, jlong lamePtr) {
    lame_global_flags *lameFlags;
    lameFlags = (lame_global_flags *) lamePtr;
    return lame_get_version(lameFlags);
}

// 转换wav文件为mp3文件
JNIEXPORT jint JNICALL Java_net_qiujuer_lame_Lame_convertWavToMp3(
        JNIEnv *env, jobject thiz,
        jstring wav_file_path,
        jstring mp3_file_path,
        jint sample_rate,
        jint channels,
        jint bit_rate,
        jlong timestamp) {

    const char *wavPath = env->GetStringUTFChars(wav_file_path, NULL);
    const char *mp3Path = env->GetStringUTFChars(mp3_file_path, NULL);

    // ==== 打开输入文件 ====
    FILE *wavFile = fopen(wavPath, "rb");
    if (!wavFile) {
        // 打开WAV文件失败
        return -1;
    }
    fseek(wavFile, 44, SEEK_SET);  // 跳过WAV头

    // ==== 初始化 LAME ====
    lame_global_flags *lame = lame_init();
    lame_set_in_samplerate(lame, sample_rate);
    lame_set_num_channels(lame, channels);
    lame_set_brate(lame, bit_rate);
    lame_set_VBR(lame, vbr_default);

    // ==== 关键修复1：启用VBR头写入 ====
    lame_set_bWriteVbrTag(lame, 1);  // 必须启用！

    // ==== 关键修复2：使用标准ID3标签设置（兼容方案） ====
    char timestamp_str[64];
    snprintf(timestamp_str, sizeof(timestamp_str), "%lld", timestamp);

    // 安全设置标题和注释（避免UTF16问题）
    id3tag_set_title(lame, timestamp_str);
    id3tag_set_comment(lame, "Recording timestamp");

    lame_init_params(lame);

    // ==== 准备缓冲区 ====
    const int PCM_SIZE = 1152 * 2;
    const int MP3_SIZE = 7200;
    short pcmBuffer[PCM_SIZE * channels];
    unsigned char mp3Buffer[MP3_SIZE];

    // ==== 关键修复3：使用读写模式打开MP3文件 ====
    FILE *mp3File = fopen(mp3Path, "wb+");  // 注意"wb+"模式
    if (!mp3File) {
        return -1;
    }

    // ==== 转换循环 ====
    size_t read;
    while ((read = fread(pcmBuffer, sizeof(short), PCM_SIZE, wavFile)) > 0) {
        int samples = read / channels;
        int encodedSize;

        if (channels == 2) {
            encodedSize = lame_encode_buffer_interleaved(
                    lame, pcmBuffer, samples, mp3Buffer, MP3_SIZE);
        } else {
            encodedSize = lame_encode_buffer(
                    lame, pcmBuffer, NULL, samples, mp3Buffer, MP3_SIZE);
        }

        if (encodedSize > 0) {
            fwrite(mp3Buffer, 1, encodedSize, mp3File);
        }
    }

    // ==== 最终刷新编码器 ====
    int encodedSize = lame_encode_flush(lame, mp3Buffer, MP3_SIZE);
    if (encodedSize > 0) {
        fwrite(mp3Buffer, 1, encodedSize, mp3File);
    }

    // ==== 关键修复4：写入VBR头（解决播放时长问题） ====
    if (lame_get_bWriteVbrTag(lame)) {
        // 必须在文件末尾调用此函数
        lame_mp3_tags_fid(lame, mp3File);
    }

    // ==== 清理资源 ====
    lame_close(lame);
    fclose(wavFile);
    fclose(mp3File);

    env->ReleaseStringUTFChars(wav_file_path, wavPath);
    env->ReleaseStringUTFChars(mp3_file_path, mp3Path);

    return 0;
}

JNIEXPORT jint JNICALL
Java_net_qiujuer_lame_Lame_mGetMp3bufferSize(JNIEnv *env, jclass type, jlong lamePtr) {
    lame_global_flags *lameFlags;
    lameFlags = (lame_global_flags *) lamePtr;
    return lame_get_size_mp3buffer(lameFlags);
}

JNIEXPORT jint JNICALL
Java_net_qiujuer_lame_Lame_mGetMp3bufferSizeWithSamples(JNIEnv *env, jclass type, jlong lamePtr,
                                                        jint samples) {

    lame_global_flags *lameFlags;
    lameFlags = (lame_global_flags *) lamePtr;

    int version = lame_get_version(lameFlags);
    int bitrate = lame_get_brate(lameFlags);
    int sampleRate = lame_get_out_samplerate(lameFlags);

    float p = (bitrate / 8.0f) / sampleRate;

    if (version == 0) {
        // MPEG2: num_samples*(bitrate/8)/samplerate + 4*576*(bitrate/8)/samplerate + 256
        return (jint) ceil(samples * p + 4 * 576 * p + 256);
    } else if (version == 1) {
        // MPEG1: num_samples*(bitrate/8)/samplerate + 4*1152*(bitrate/8)/samplerate + 512
        return (jint) ceil(samples * p + 4 * 1152 * p + 512);
    } else {
        return (jint) ceil((1.25 * samples + 7200));
    }
}

JNIEXPORT jint JNICALL
Java_net_qiujuer_lame_Lame_nEncodeShortInterleaved(JNIEnv *env, jclass type, jlong lamePtr,
                                                   jshortArray bufLR_, jint samples,
                                                   jbyteArray outMp3buf_) {

    lame_global_flags *lameFlags;
    lameFlags = (lame_global_flags *) lamePtr;

    jshort *bufLR = env->GetShortArrayElements(bufLR_, NULL);
    jbyte *outMp3buf = env->GetByteArrayElements(outMp3buf_, NULL);

    const jsize outMp3bufSize = env->GetArrayLength(outMp3buf_);
    int result = lame_encode_buffer_interleaved(lameFlags, bufLR, samples,
                                                (u_char *) outMp3buf, outMp3bufSize);

    env->ReleaseShortArrayElements(bufLR_, bufLR, 0);
    env->ReleaseByteArrayElements(outMp3buf_, outMp3buf, 0);

    return result;
}

JNIEXPORT jint JNICALL
Java_net_qiujuer_lame_Lame_nEncodeShort(JNIEnv *env, jclass type, jlong lamePtr, jshortArray bufL_,
                                        jshortArray bufR_, jint samples, jbyteArray outMp3buf_) {
    lame_global_flags *lameFlags;
    lameFlags = (lame_global_flags *) lamePtr;

    jshort *bufL = env->GetShortArrayElements(bufL_, NULL);
    jshort *bufR = env->GetShortArrayElements(bufR_, NULL);
    jbyte *outMp3buf = env->GetByteArrayElements(outMp3buf_, NULL);

    const jsize outMp3bufSize = env->GetArrayLength(outMp3buf_);
    int result = lame_encode_buffer(lameFlags, bufL, bufR, samples,
                                    (u_char *) outMp3buf, outMp3bufSize);

    env->ReleaseShortArrayElements(bufL_, bufL, 0);
    env->ReleaseShortArrayElements(bufR_, bufR, 0);
    env->ReleaseByteArrayElements(outMp3buf_, outMp3buf, 0);

    return result;
}

JNIEXPORT jint JNICALL
Java_net_qiujuer_lame_Lame_nFlush(JNIEnv *env, jclass type, jlong lamePtr, jbyteArray outBuf_) {

    lame_global_flags *lameFlags;
    lameFlags = (lame_global_flags *) lamePtr;

    jbyte *outBuf = env->GetByteArrayElements(outBuf_, NULL);

    const jsize outBufSize = env->GetArrayLength(outBuf_);
    int result = lame_encode_flush(lameFlags, (u_char *) outBuf, outBufSize);

    env->ReleaseByteArrayElements(outBuf_, outBuf, 0);

    return result;
}

JNIEXPORT void JNICALL
Java_net_qiujuer_lame_Lame_nClose(JNIEnv *env, jclass type, jlong lamePtr) {
    lame_global_flags *lameFlags;
    lameFlags = (lame_global_flags *) lamePtr;
    lame_close(lameFlags);
}